/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#include "StdAfx.h"
#include "MFile.h"
#include "physfs.h"

#include <iostream>
#include <fstream>

// helper function
bool IsNumber( char c )
{
    // a number
    char nums[] = { '0', '1', '2', '3', '4',
                    '5', '6', '7', '8', '9',
    };

    // search the array
    for ( int i = 0; i < 10; i++ )
    {
        // if we have a match
        // it is a number
        if ( c == nums[i] )
            return true;
    }
    return false;
}



/**
=========================================
Myriad File System
=========================================
*/


MFile::MFile(void)
{
    m_position = 0;
    m_data  = NULL;
    m_size = 0;
}


/** Open a file */
bool MFile::Open( const std::string &filename )
{
    m_name = filename;
    if ( PHYSFS_exists( filename.c_str() ) )
    {
        m_opened = true;
        PHYSFS_file* phyFile = PHYSFS_openRead( filename.c_str() );
        if ( !phyFile ) return true; // error
        m_size =  PHYSFS_fileLength( phyFile );

        m_data = new char[ m_size ];
        PHYSFS_read (phyFile, m_data, 1 , m_size );

        // close the file
        PHYSFS_close( phyFile );
    } 
    else
    {
        // file
        std::ifstream file;
        // open a stream to the file
        file.open( filename.c_str(), std::ios::ate );

        m_opened = file.good();
        if ( !m_opened )
            return true;

        // fetch the size
        m_size = file.tellg();
        file.seekg(0, std::ios::beg );

        m_data = new char[ m_size ];
        file.read( m_data, m_size );

    }
    return false;
}


/** Close the stream */
void MFile::Close()
{
    if ( m_opened ) {
       delete m_data;
       m_data = NULL;

       m_opened = false;
    }
}

/** Read the next line */
std::string MFile::ReadLine()
{
    return ReadNext( "\n", false, false, false );
}

/** Read the next delimeter */
std::string MFile::ReadNext( const std::string &delim, bool ignoreReturn, bool ignoreWhiteSpace, bool ignoreTab )
{
    // line to return
    std::string line;
    // next character in the stream
    char c;
    // number to delimeter length
    int todelim = 0;
    // first actual letter
    bool firstLetterFound = false;

    while( !IsEnd() )
    {
        // read in next char in stream
        c = Read();

        //if ( c == 0x0d ) continue;
        if ( c == '\n' && ignoreReturn )
            continue;
        if ( c == '\t' && ignoreTab && !firstLetterFound)
            continue;
        if ( c == ' ' && ignoreWhiteSpace && !firstLetterFound )
            continue; 

        firstLetterFound = true;
        // append to our line
        line += c;

        // get the new length
        size_t ndel = (line.length() - todelim);

        // if we reached our delimeter, return the line
        if ( delim.compare( 0, delim.length(), line, todelim, ndel ) == 0 )
            return line.substr(0, todelim );
        // else increment our delimeter length if we don't match our delimeter
        else if ( delim.compare( 0, ndel, line.substr( todelim, ndel ) ) != 0)
            todelim++;
    }
    return line; 
}


/** Read a number */
std::string MFile::ReadNumber(bool decimal)
{
    std::string number;
    bool found = false; 
    bool first = true;
    while( !IsEnd() )
    {
        char c = Read();

        // check for negative sign
        if ( first )
        {
            if ( c == '-' )
            {
                number += c;
                first = false;
                continue;
            }
        }
        // skip a return statement or white space
        if ( number.empty() && (c == '\n'|| c == 32||c == '\t' ) )
            continue;
        // add if it is a number
        if ( IsNumber( c ) )
            number += c;
        // if we allow a decimal, make sure there
        // is only one decimal
        else if ( c == '.' && decimal && !found )
        {
            // decimal has been found
            found = true;
            // look at the next char to see if there is
            // a number
            if ( !IsEnd() && IsNumber( Peek() ) )
                number += c;
            else
                return number;
        } else
            // return the number
            return number;
    } 
    return number;
}
/** Read the next number */
double MFile::ReadDouble()
{
    std::string num = ReadNumber( true );
    return atof( num.c_str() );
}

/** Read the next int */
int MFile::ReadInt()
{
    std::string num = ReadNumber( false );
    return atoi( num.c_str() );
}

/** Get a single byte */
char MFile::Read()
{
    // will only be one in a sequence of NULL
    // terminating... this is due to how
    // PHYSFS handles NULL terminating strings
    if ( m_data [ m_position ] == 0x0d )
    {
        if ( ! IsEnd() )
        {
            ++m_position; // skip the null char
        }
    }
    return m_data[ m_position++ ]; // update the pos
}

/** Peek at the next char in the stream */
char MFile::Peek()
{
    return m_data[ m_position ];
}

/** Seek to a location */
void MFile::Seek( int position )
{
    if ( m_data )
    {
        if ( position < m_size && position >= 0 )
        {
            m_position = position;
        }
    }
}

/** End of File */
bool MFile::IsEnd()
{
    return m_position >= m_size;
}

/** Set Data */
void MFile::SetData( char* buf, int size )
{
    if ( m_data ) delete m_data;
    m_data = buf;
    m_size = size;
}

MFile::~MFile(void)
{
    Close();
}
